<!DOCTYPE html>
<html>
    
<head>
    <meta charset="utf-8">
    
    <title>Android全新UI编程 - Jetpack Compose 超详细教程 第1弹 | ApocalypseBlog</title>
    <canvas id="header_canvas"style="position:absolute;bottom:0"></canvas> 
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    

    

    

    

    
<link rel="stylesheet" href="/dist/build.css?v=1.14.0.css">

    <script src="/javascripts/bubble.js"></script>
    <script>
        window.isPost = true
        window.aomori = {
            
            
        }
        window.aomori_logo_typed_animated = false
        window.aomori_search_algolia = false

    </script>
<script>
    ((window.gitter = {}).chat = {}).options = {
      room: 'ApocalypseBlog/Apocalypse'
    };
  </script>
  <script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer></script>
<meta name="generator" content="Hexo 5.3.0"></head>
<!--DaoVoice服务http://blog.daovoice.io/-->

    <script>(function (i, s, o, g, r, a, m) {
        i['DaoVoiceObject'] = r;
        i[r] = i[r] ||
          function () {
            (i[r].q = i[r].q || []).push(arguments);
          };
        i[r].l = 1 * new Date();
        a = s.createElement(o);
        m = s.getElementsByTagName(o)[0];
        a.async = 1;
        a.src = g;
        a.charset = 'utf-8';
        m.parentNode.insertBefore(a, m);
      })(window, document, 'script', ('https:' === document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/b00f5052.js", 'daovoice');
      daovoice('init', {
        app_id: "b00f5052",
      });
      daovoice('update');
    </script>
  
<body>

    <div class="container">
    <header class="header">
        <div class="header-type">
            
            <div class="header-type-inner">
                
                    <a class="header-type-title" href="/">ApocalypseBlog</a>
                
    
                
            </div>
        </div>
        <div class="header-menu">
            <div class="header-menu-inner">
                
            </div>
            <div class="header-menu-social">
                
            </div>
        </div>

        <div class="header-menu-mobile">
            <div class="header-menu-mobile-inner" id="mobile-menu-open">
                <i class="icon icon-menu"></i>
            </div>
        </div>
    </header>

    <div class="header-menu-mobile-menu">
        <div class="header-menu-mobile-menu-bg"></div>
        <div class="header-menu-mobile-menu-wrap">
            <div class="header-menu-mobile-menu-inner">
                <div class="header-menu-mobile-menu-close" id="mobile-menu-close">
                    <i class="icon icon-cross"></i>
                </div>
                <div class="header-menu-mobile-menu-list">
                    
                </div>
            </div>
        </div>
    </div>

</div>

    <div class="container">
        <div class="main">
            <section class="inner">
                <section class="inner-main">
                    <div class="post">
    <article id="post-ckk6o6aug00037knyf7zc77r9" class="article article-type-post" itemscope
    itemprop="blogPost">

    <div class="article-inner">

        
          
        
        
        

        
        <header class="article-header">
            
  
    <h1 class="article-title" itemprop="name">
      Android全新UI编程 - Jetpack Compose 超详细教程 第1弹
    </h1>
  

        </header>
        

        <div class="article-more-info article-more-info-post hairline">

            <div class="article-date">
  <time datetime="2020-07-26T19:45:38.000Z" itemprop="datePublished">2020-07-27</time>
</div>

            

            

            

        </div>

        <div class="article-entry post-inner-html hairline" itemprop="articleBody">
            <h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a><strong>1. 简介</strong></h2><p><code>Jetpack Compose</code>是在2019Google i/O大会上发布的新的库。<code>Compose</code>库是用响应式编程的方式对View进行构建,可以用更少更直观的代码，更强大的功能，能提高开发速度（这一段是谷歌自己说的）。 说实话，<code>View/Layout</code>的模式对安卓工程师来说太过于熟悉，对于学习曲线陡峭的<code>Jetpack Compose</code>能不能很好的普及还是有所担心。</p>
<a id="more"></a>

<p>因为<code>Jetpack Compose</code>的内容比较多，我会分成多个文章来进行介绍。 内容包括常用UI组件的使用，<code>Flow</code>和<code>Compose</code>的结合使用，以及如何构建MVVM应用。 还有，<code>Compose</code>的API还没有完全的确定下来，如果有API的修改，我也会对文章进行修订，所以敬请放心。</p>
<p>第1弹将会介绍如何创建<code>Compose</code>应用以及基本注解，<code>Compose</code>方法的使用。 好了，闲话不多说，开整!</p>
<h2 id="2-教程"><a href="#2-教程" class="headerlink" title="2. 教程"></a><strong>2. 教程</strong></h2><h3 id="2-1-创建新的项目或导入库"><a href="#2-1-创建新的项目或导入库" class="headerlink" title="2.1 创建新的项目或导入库"></a>2.1 创建新的项目或导入库</h3><p><code>Jetpack Compose</code>是从<code>Android Studio 4.2</code>开始支持的，所以需要通过4.2(现在是canary版本)创建新的项目或者添加导入库。这里按照创建新的项目来进行介绍。</p>
<p><img src="http://user-gold-cdn.xitu.io/2020/7/11/1733d12417c46b93?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="img"></p>
<p>根据上图所示，在创建新的项目时需要选择<code>Empty Compose Activity</code>。</p>
<p>此时模块中的<code>build.gradle</code>文件会新增下列的库的依赖。</p>
<pre><code class="kotlin">dependencies &#123;
    ...
    implementation &#39;androidx.ui:ui-layout:&quot;$&#123;compose_version&#125;&quot;&#39;
    implementation &#39;androidx.ui:ui-material:&quot;$&#123;compose_version&#125;&quot;&#39;
    implementation &#39;androidx.ui:ui-tooling:&quot;$&#123;compose_version&#125;&quot;&#39;
    ...
&#125;
</code></pre>
<p>还有在模块的<code>build.gradle</code>文件中新增下列的设置。</p>
<pre><code class="kotlin">android &#123;
    ...

    buildFeatures &#123;
        compose true
    &#125;

    composeOptions &#123;
        kotlinCompilerExtensionVersion &quot;$&#123;compose_version&#125;&quot;

        kotlinCompilerVersion &quot;1.3.70-dev-withExperimentalGoogleExtensions-20200424&quot;
    &#125;
&#125;
</code></pre>
<h3 id="2-2-UI相关"><a href="#2-2-UI相关" class="headerlink" title="2.2 UI相关"></a>2.2 UI相关</h3><h4 id="2-2-1-Compose"><a href="#2-2-1-Compose" class="headerlink" title="2.2.1 @Compose"></a>2.2.1 @Compose</h4><p>所有关于构建View的方法都必须添加<code>@Compose</code>的注解才可以。并且<code>@Compose</code>跟协程的<code>Suspend</code>的使用方法比较类似,被<code>@Compose</code>的注解的方法只能在同样被<code>@Comopse</code>注解的方法中才能被调用。</p>
<pre><code class="kotlin">@Composable
fun Greeting(name: String) &#123;
    Text(text = &quot;Hello $name!&quot;)
&#125;
</code></pre>
<h4 id="2-2-2-Preview"><a href="#2-2-2-Preview" class="headerlink" title="2.2.2 @Preview"></a>2.2.2 @Preview</h4><p>加上<code>@Preview</code>注解的方法可以在不运行App的情况下就可以确认布局的情况。</p>
<p><code>@Preview</code>的注解中比较常用的参数如下：</p>
<ol>
<li><code>name: String</code>: 为该Preview命名，该名字会在布局预览中显示。</li>
<li><code>showBackground: Boolean</code>: 是否显示背景，true为显示。</li>
<li><code>backgroundColor: Long</code>: 设置背景的颜色。</li>
<li><code>showDecoration: Boolean</code>: 是否显示Statusbar和Toolbar，true为显示。</li>
<li><code>group: String</code>: 为该Preview设置group名字，可以在UI中以group为单位显示。</li>
<li><code>fontScale: Float</code>: 可以在预览中对字体放大，范围是从0.01。</li>
<li><code>widthDp: Int</code>: 在Compose中渲染的最大宽度，单位为dp。</li>
<li><code>heightDp: Int</code>: 在Compose中渲染的最大高度，单位为dp。</li>
</ol>
<p>上面的参数都是可选参数，还有像背景设置等的参数并<strong>不是</strong>对实际的App进行设置，只是对Preview中的背景进行设置，为了更容易看清布局。</p>
<pre><code class="kotlin">@Preview(showBackground = true, name = &quot;Home UI&quot;, showDecoration = true)
@Composable
fun DefaultPreview() &#123;
    MyApplicationTheme &#123;
        Greeting(&quot;Android&quot;)
    &#125;
&#125;
</code></pre>
<p>在IDE的右上角有<code>Code</code>，<code>Split</code>,<code>Design</code>三个选项。分别是只显示代码，同时显示代码和布局和只显示布局。<br> 当更改跟UI相关的代码时，会显示一个横条通知，点击<code>Build&amp;Refresh</code>即可更新显示所更改代码的UI。</p>
<h4 id="2-2-3-setContent"><a href="#2-2-3-setContent" class="headerlink" title="2.2.3 setContent"></a>2.2.3 setContent</h4><p><code>setContent</code>的作用是和zai<code>Layout/View</code>中的<code>setContentView</code>是一样的。<br> <code>setContent</code>的方法也是有<code>@Compose</code>注解的方法。所以，在<code>setContent</code>中写入关于UI的<code>@Compopse</code>方法，即可在Activity中显示。</p>
<pre><code class="kotlin">    override fun onCreate(savedInstanceState: Bundle?) &#123;
        super.onCreate(savedInstanceState)
        setContent &#123;
            JetpackComposeDemoTheme &#123;
                Greeting(&quot;Android&quot;)
            &#125;
        &#125;
    &#125;
</code></pre>
<h4 id="2-2-4-Theme"><a href="#2-2-4-Theme" class="headerlink" title="2.2.4 *Theme"></a>2.2.4 *Theme</h4><p>在创建新的Compose项目时会自动创建一个<code>项目名+Theme</code>的<code>@Compose</code>方法。 我们可以通过更改颜色来完成对主题颜色的设置。 生成的Theme方法的代码如下。</p>
<pre><code class="kotlin">private val DarkColorPalette = darkColorPalette(
        primary = purple200,
        primaryVariant = purple700,
        secondary = teal200
)

private val LightColorPalette = lightColorPalette(
        primary = purple500,
        primaryVariant = purple700,
        secondary = teal200

        /* Other default colors to override
    background = Color.White,
    surface = Color.White,
    onPrimary = Color.White,
    onSecondary = Color.Black,
    onBackground = Color.Black,
    onSurface = Color.Black,
    */
)

@Composable
fun JetpackComposeDemoTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -&gt; Unit) &#123;
    val colors = if (darkTheme) &#123;
        DarkColorPalette
    &#125; else &#123;
        LightColorPalette
    &#125;

    MaterialTheme(
            colors = colors,
            typography = typography,
            shapes = shapes,
            content = content
    )
&#125;
</code></pre>
<p>Theme方法中有正常主题和Dark主题的颜色设置，里面还有关于<code>MeterialTheme</code>的设置。</p>
<p>关于Theme方法的用法如下。</p>
<pre><code class="kotlin">        setContent &#123;
            JetpackComposeDemoTheme &#123;
                Greeting(&quot;Android&quot;)
            &#125;
        &#125;
</code></pre>
<p>在<code>JetpackComposeDemoTheme</code>里面的所有UI方法都会应用上述主题中指定的颜色。</p>
<h4 id="2-2-4-Modifier"><a href="#2-2-4-Modifier" class="headerlink" title="2.2.4 Modifier"></a>2.2.4 Modifier</h4><p><code>Modifier</code>是各个<code>Compose</code>的UI组件一定会用到的一个类。它是被用于设置UI的摆放位置，padding等信息的类。关于<code>Modifier</code>相关的设置实在是太多，在这里只介绍会经常用到的。</p>
<ul>
<li><code>padding</code> 设置各个UI的padding。padding的重载的方法一共有四个。</li>
</ul>
<pre><code class="kotlin">Modifier.padding(10.dp) // 给上下左右设置成同一个值
Modifier.padding(10.dp, 11.dp, 12.dp, 13.dp) // 分别为上下左右设值
Modifier.padding(10.dp, 11.dp) // 分别为上下和左右设值
Modifier.padding(InnerPadding(10.dp, 11.dp, 12.dp, 13.dp))// 分别为上下左右设值
</code></pre>
<p>这里设置的值必须为<code>Dp</code>，<code>Compose</code>为我们在Int中扩展了一个方法<code>dp</code>，帮我们转换成<code>Dp</code>。</p>
<ul>
<li><code>plus</code> 可以把其他的Modifier加入到当前的Modifier中。</li>
</ul>
<pre><code class="kotlin">Modifier.plus(otherModifier) // 把otherModifier的信息加入到现有的modifier中
</code></pre>
<ul>
<li><code>fillMaxHeight</code>,<code>fillMaxWidth</code>,<code>fillMaxSize</code> 类似于<code>match_parent</code>,填充整个父layout。</li>
</ul>
<pre><code class="kotlin">Modifier.fillMaxHeight() // 填充整个高度
</code></pre>
<ul>
<li><code>width</code>,<code>heigh</code>,<code>size</code> 设置Content的宽度和高度。</li>
</ul>
<pre><code class="kotlin">Modifier.width(2.dp) // 设置宽度
Modifier.height(3.dp)  // 设置高度
Modifier.size(4.dp, 5.dp) // 设置高度和宽度
</code></pre>
<ul>
<li><code>widthIn</code>, <code>heightIn</code>, <code>sizeIn</code> 设置Content的宽度和高度的最大值和最小值。</li>
</ul>
<pre><code class="kotlin">Modifier.widthIn(2.dp) // 设置最大宽度
Modifier.heightIn(3.dp) // 设置最大高度
Modifier.sizeIn(4.dp, 5.dp, 6.dp, 7.dp) // 设置最大最小的宽度和高度
</code></pre>
<ul>
<li><code>gravity</code> 在<code>Column</code>中元素的位置。</li>
</ul>
<pre><code class="kotlin">Modifier.gravity(Alignment.CenterHorizontally) // 横向居中
Modifier.gravity(Alignment.Start) // 横向居左
Modifier.gravity(Alignment.End) // 横向居右
</code></pre>
<ul>
<li><code>rtl</code>, <code>ltr</code> 开始布局UI的方向。</li>
</ul>
<pre><code class="kotlin">Modifier.rtl  // 从右到左
Modifier.ltr  // 从左到右
</code></pre>
<p>Modifier的方法都返回Modifier的实例的链式调用，所以只要连续调用想要使用的方法即可。</p>
<pre><code class="kotlin">@Composable
fun Greeting(name: String) &#123;
    Text(text = &quot;Hello $name!&quot;, modifier = Modifier.padding(20.dp).fillMaxSize())
&#125;
</code></pre>
<h4 id="2-2-5-Column，Row"><a href="#2-2-5-Column，Row" class="headerlink" title="2.2.5 Column，Row"></a>2.2.5 Column，Row</h4><p>正如其名字一样，<code>Column</code>和<code>Row</code>可以理解为在<code>View/Layout</code>体系中的纵向和横向的<code>ViewGroup</code>。<br> 需要传入的参数一共有四个。</p>
<ul>
<li><code>Modifier</code> 用上述的方法传入已经按需求设置好的Modifier即可。</li>
<li><code>Arrangement.Horizontal</code>,  <code>Arrangement.Vertical</code> 需要给<code>Row</code>传入<code>Arrangement.Horizontal</code>，为<code>Column</code>传入<code>Arrangement.Vertical</code>。 这些值决定如何布置内部UI组件。<br> 可传入的值为<code>Center</code>, <code>Start</code>, <code>End</code>, <code>SpaceEvenly</code>, <code>SpaceBetween</code>, <code>SpaceAround</code>。 重点解释一下<code>SpaceEvenly</code>, <code>SpaceBetween</code>, <code>SpaceAround</code>。</li>
</ul>
<p><code>SpaceEvenly</code>：各个元素间的空隙为等比例。<br><code>SpaceBetween</code>：第一元素前和最后一个元素之后没有空隙，所有空隙都按等比例放入各个元素之间。 <code>SpaceAround</code>：把整体中一半的空隙平分的放入第一元素前和最后一个元素之后，剩余的一半等比例的放入各个元素之间。</p>
<ul>
<li><code>Alignment.Vertical</code>, <code>Alignment.Horizontal</code> 需要给<code>Row</code>传入<code>Alignment.Vertical</code>，为<code>Column</code>传入<code>Alignment.Horizontal</code>。 使用方法和<code>Modifier</code>的<code>gravity</code>中传入参数的用法是一样的，这里就略过了。</li>
<li><code>@Composable ColumnScope.() -&gt; Unit</code> 需要传入标有<code>@Compose</code>的UI方法。但是这里我们会有lamda函数的写法来实现。</li>
</ul>
<p>整体代码如下。</p>
<pre><code class="kotlin">Column &#123;
        Row(modifier = Modifier.ltr.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceAround, verticalGravity = Alignment.Top) &#123;
       // ..,...
    &#125;
</code></pre>
<p><img src="http://user-gold-cdn.xitu.io/2020/7/11/1733d12458fd18d5?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="img"></p>

        </div>

    </div>

    

    

    

    

    

    
<nav class="article-nav">
  
    <a href="/2020/08/03/%E8%BF%9915%E4%B8%AAAndroid%E5%BC%80%E6%BA%90%E5%BA%93%EF%BC%8C%E5%8F%AA%E6%9C%89%E7%BB%8F%E5%B8%B8%E9%80%9BGithub%E7%9A%84%E6%89%8D%E7%9F%A5%E9%81%93%EF%BC%81/" id="article-nav-newer" class="article-nav-link-wrap">
      <div class="article-nav-caption">下一篇</div>
      <div class="article-nav-title">
        
          这15个Android开源库，只有经常逛Github的才知道！
        
      </div>
    </a>
  
  
    <a href="/2020/07/25/Android%E8%BF%9B%E9%98%B6%E5%9F%BA%E7%A1%80%E7%B3%BB%E5%88%97%EF%BC%9AView%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86-%E5%85%A8%E9%9D%A2%E7%90%86%E8%A7%A3%EF%BC%81/" id="article-nav-older" class="article-nav-link-wrap">
      <div class="article-nav-caption">上一篇</div>
      <div class="article-nav-title">Android进阶基础系列：View的工作原理 全面理解！</div>
    </a>
  
</nav>


    <section class="share">
        <div class="share-title">分享</div>
        <a class="share-item" target="_blank"
            href="https://twitter.com/share?text=Android全新UI编程 - Jetpack Compose 超详细教程 第1弹 - ApocalypseBlog&url=http://example.com/2020/07/27/Android%E5%85%A8%E6%96%B0UI%E7%BC%96%E7%A8%8B-Jetpack-Compose-%E8%B6%85%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B-%E7%AC%AC1%E5%BC%B9/">
            <box-icon type='logo' name='twitter'></box-icon>
        </a>
        <a class="share-item" target="_blank"
            href="https://www.facebook.com/sharer.php?title=Android全新UI编程 - Jetpack Compose 超详细教程 第1弹 - ApocalypseBlog&u=http://example.com/2020/07/27/Android%E5%85%A8%E6%96%B0UI%E7%BC%96%E7%A8%8B-Jetpack-Compose-%E8%B6%85%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B-%E7%AC%AC1%E5%BC%B9/">
            <box-icon name='facebook-square' type='logo' ></box-icon>
        </a>
        <!-- <a class="share-item" target="_blank"
            href="https://service.weibo.com/share/share.php?title=Android全新UI编程 - Jetpack Compose 超详细教程 第1弹 - ApocalypseBlog&url=http://example.com/2020/07/27/Android%E5%85%A8%E6%96%B0UI%E7%BC%96%E7%A8%8B-Jetpack-Compose-%E8%B6%85%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B-%E7%AC%AC1%E5%BC%B9/&pic=">
            <div class="n-icon n-icon-weibo"></div>
        </a> -->
    </section>

</article>









</div>
                </section>
            </section>

             
            <aside class="sidebar">
            
                
            </aside>
        </div>
    </div>

    <footer class="footer">
    <div class="footer-wave">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"><path fill="#3c4859" fill-opacity="1" d="M0,160L60,181.3C120,203,240,245,360,240C480,235,600,181,720,186.7C840,192,960,256,1080,261.3C1200,267,1320,213,1380,186.7L1440,160L1440,320L1380,320C1320,320,1200,320,1080,320C960,320,840,320,720,320C600,320,480,320,360,320C240,320,120,320,60,320L0,320Z"></path></svg>
    </div>

    <div class="footer-wrap">
        <div class="footer-inner"> 
            ApocalypseBlog &copy; 2021<br>
            Powered By Hexo · Theme By <a href="https://github.com/lh1me/hexo-theme-aomori" target="_blank">Aomori</a>
        </div>
    </div>

</footer>




<script src="/dist/build.js?1.14.0.js"></script>


<script src="/dist/custom.js?1.14.0.js"></script>









</body>

</html>